package com.wechatapp.mengyao.poetry.core;

import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * @author yanghuaxu
 * @date 2025/6/11 11:00
 */
@RestControllerAdvice
public class JsonFieldFilterResponseAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 永远支持，Spring 会根据是否是 MappingJackson2HttpMessageConverter 自动判断
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
                                  MediaType contentType, Class<? extends HttpMessageConverter<?>> converterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {

        JsonFieldFilterDef filterDef = getJsonFieldFilterDef(returnType);
        if (filterDef == null || body == null) {
            return body; // 不需要处理
        }

        MappingJacksonValue wrapper = new MappingJacksonValue(body);
        wrapper.setFilters(buildFilters(filterDef));
        return wrapper;
    }

    private JsonFieldFilterDef getJsonFieldFilterDef(MethodParameter returnType) {
        // 优先取方法上的
        JsonFieldFilterDef def = returnType.getMethodAnnotation(JsonFieldFilterDef.class);
        if (def == null) {
            // 再尝试类上的
            def = returnType.getContainingClass().getAnnotation(JsonFieldFilterDef.class);
        }
        return def;
    }

    private FilterProvider buildFilters(JsonFieldFilterDef filterDef) {
        SimpleFilterProvider provider = new SimpleFilterProvider();
        for (JsonFieldFilterDef.Entry entry : filterDef.value()) {
            Class<?> clazz = entry.type();
            JsonFilter filter = clazz.getAnnotation(JsonFilter.class);
            String filterId = (filter != null) ? filter.value() : clazz.getName();

            SimpleBeanPropertyFilter actualFilter;
            if (entry.include().length > 0) {
                actualFilter = SimpleBeanPropertyFilter.filterOutAllExcept(new HashSet<>(Arrays.asList(entry.include())));
            } else {
                actualFilter = SimpleBeanPropertyFilter.serializeAllExcept(new HashSet<>(Arrays.asList(entry.exclude())));
            }

            provider.addFilter(filterId, actualFilter);
        }
        provider.setFailOnUnknownId(false);
        return provider;
    }
}
